home *** CD-ROM | disk | FTP | other *** search
/ ftp.mactech.com 2010 / ftp.mactech.com.tar / ftp.mactech.com / macintosh-c / macc-carbon-demos-nonbinhex.sit / macc-carbon-demos-nonbinhex / chap23-demo-classic events / ReceiveAndUndoDrag.c < prev    next >
Text File  |  2001-05-31  |  10KB  |  314 lines

  1. // *******************************************************************************************
  2. // ReceiveAndUndoDrag.c
  3. // *******************************************************************************************
  4.  
  5. // ………………………………………………………………………………………………………………………………………………………………………………………………………………………… includes
  6.  
  7. #include "Drag.h"
  8.  
  9. // …………………………………………………………………………………………………………………………………………………………………………………………………… global variables
  10.  
  11. extern Boolean    gEnableDragUndoRedoItem;
  12. extern Boolean    gUndoFlag;
  13. extern Boolean    gCanAcceptItems;
  14. extern SInt16        gInsertPosition, gCaretOffset;
  15.  
  16. // ************************************************************************ dragReceiveHandler
  17.  
  18. OSErr  dragReceiveHandler(WindowRef windowRef,void *handlerRefCon,DragRef dragRef)
  19. {
  20.     docStructurePointer    docStrucPtr;
  21.     TEHandle                        textEditStrucHdl;
  22.     SInt32                            totalTextStart;
  23.     Size                                totalTextSize;
  24.     Boolean                            wasActive, moveText, gotUndoMemory = false;
  25.     DragAttributes            dragAttributes;
  26.     SInt16                            mouseDownModifiers, mouseUpModifiers, selStart, selEnd;
  27.     UInt16                            numberOfDragItems, index;
  28.     ItemReference                itemReference;
  29.     OSErr                                osError;
  30.     Size                                textSize;
  31.     Ptr                                    textDataPtr;
  32.     SInt32                            additionalChars;
  33.  
  34.     if((!gCanAcceptItems) || (gInsertPosition == -1))
  35.         return dragNotAcceptedErr;
  36.  
  37.     docStrucPtr = (docStructurePointer) handlerRefCon;        
  38.     textEditStrucHdl = docStrucPtr->textEditStrucHdl;
  39.  
  40.     // … set graphics port to this window's port and, if necessary, activate text edit structure
  41.  
  42.     SetPortWindowPort(windowRef);
  43.  
  44.     wasActive = (*textEditStrucHdl)->active != 0;
  45.     if(!wasActive)
  46.         TEActivate(textEditStrucHdl);
  47.  
  48.     // ………………………………………………………………………………………………………………………… get drag attributes and keyboard modifiers
  49.  
  50.     GetDragAttributes(dragRef,&dragAttributes);
  51.     GetDragModifiers(dragRef,0L,&mouseDownModifiers,&mouseUpModifiers);
  52.  
  53.     // … … …  in case their are multiple items, save first insertion point for later TESetSelect
  54.  
  55.     totalTextStart = gInsertPosition;
  56.     totalTextSize = 0;
  57.  
  58.     // … … for all items in drag, get 'TEXT' data, insert into this window's text edit structure
  59.  
  60.     CountDragItems(dragRef,&numberOfDragItems);
  61.  
  62.     for(index=1;index <= numberOfDragItems;index++)
  63.     {
  64.         GetDragItemReferenceNumber(dragRef,index,&itemReference);
  65.  
  66.         osError = GetFlavorDataSize(dragRef,itemReference,'TEXT',&textSize);
  67.         if(osError == noErr)
  68.         {
  69.             // …  if addition of drag to the text edit structure would exceed TextEdit limit, return
  70.  
  71.             if(((*textEditStrucHdl)->teLength + textSize) > kMaxTELength)
  72.                 return dragNotAcceptedErr;
  73.  
  74.             // … … … … … … … … … … … … … create nonrelocatable block and get the 'TEXT' data into it
  75.  
  76.             textDataPtr = NewPtr(textSize);
  77.             if(textDataPtr == NULL)
  78.                 return dragNotAcceptedErr;
  79.  
  80.             GetFlavorData(dragRef,itemReference,'TEXT',textDataPtr,&textSize,0);
  81.  
  82.             // … … … … … … … … … … … … … … … … … …  if caret or highlighting is on screen, remove it
  83.  
  84.             if(gCaretOffset != -1)
  85.             {
  86.                 doDrawCaret(gCaretOffset,textEditStrucHdl);
  87.                 gCaretOffset = -1;
  88.             }
  89.  
  90.             if(dragAttributes & kDragHasLeftSenderWindow)
  91.                 HideDragHilite(dragRef);
  92.  
  93.       // save current text and selection start/end for Undo, and set Redo/Undo menu item flags
  94.  
  95.             if(dragAttributes & kDragInsideSenderWindow)
  96.             {
  97.                 gotUndoMemory = doSavePreInsertionText(docStrucPtr);
  98.                 if(gotUndoMemory)
  99.                 {
  100.                     gEnableDragUndoRedoItem = true;
  101.                     gUndoFlag = true;
  102.                 }
  103.             }
  104.             else
  105.                 gEnableDragUndoRedoItem = false;
  106.  
  107.             // … … … … … if in sender window, ensure selected text is deleted if option key not down
  108.  
  109.             moveText = (dragAttributes & kDragInsideSenderWindow) &&
  110.                                  (!((mouseDownModifiers & optionKey) | (mouseUpModifiers & optionKey)));
  111.  
  112.             if(moveText)
  113.             {
  114.                 selStart = (*textEditStrucHdl)->selStart;
  115.                 selEnd   = (*textEditStrucHdl)->selEnd;
  116.  
  117.                 // … … … … …  extend selection by one chara if space charas just before and just after
  118.  
  119.                 if(doIsWhiteSpaceAtOffset(selStart - 1,textEditStrucHdl) &&
  120.                     !doIsWhiteSpaceAtOffset(selStart,textEditStrucHdl) &&
  121.                     !doIsWhiteSpaceAtOffset(selEnd - 1,textEditStrucHdl) &&
  122.                      doIsWhiteSpaceAtOffset(selEnd,textEditStrucHdl))
  123.                 {
  124.                     if(doGetCharAtOffset(selEnd,textEditStrucHdl) == ' ')
  125.                         (*textEditStrucHdl)->selEnd++;
  126.                 }
  127.  
  128.                 // if insertion is after selected text, move insertion point back by size of selection
  129.                 
  130.                 if(gInsertPosition > selStart)
  131.                 {
  132.                     selEnd = (*textEditStrucHdl)->selEnd;
  133.                     gInsertPosition -= (selEnd - selStart);
  134.                     totalTextStart -= (selEnd - selStart);
  135.                 }
  136.  
  137.                 // … … … …  … … … … … … … … … … … … … … … … … … … … … … … … … … … delete the selection
  138.                 
  139.                 TEDelete(textEditStrucHdl);    
  140.             }
  141.  
  142.             // … … … … … … … … … … … … … … … … … … … … insert the 'TEXT' data at the insertion point
  143.  
  144.             additionalChars = doInsertTextAtOffset(gInsertPosition,textDataPtr,textSize,
  145.                                                                                          textEditStrucHdl);
  146.  
  147.             // … … … … … if inserting multiple blocks of text, update insertion point for next block
  148.  
  149.             gInsertPosition += textSize + additionalChars;
  150.             totalTextSize += textSize + additionalChars;
  151.  
  152.             // … … … … … … … … … … … … … … … … … … … … … … … … … … … dispose of nonrelocatable block
  153.  
  154.             DisposePtr(textDataPtr);
  155.         }
  156.     }
  157.  
  158.     // …………………………………………………………………………………………………………… select total inserted text and adjust scrollbar
  159.  
  160.     TESetSelect(totalTextStart,totalTextStart + totalTextSize,textEditStrucHdl);
  161.     doAdjustScrollbar(windowRef);
  162.  
  163.     // ……………… set window's "touched" flag, and save post-insert selection start and end for Redo
  164.  
  165.     docStrucPtr->windowTouched = true;
  166.  
  167.     if(dragAttributes & kDragInsideSenderWindow)
  168.     {
  169.         docStrucPtr->postDropSelStart = totalTextStart;
  170.         docStrucPtr->postDropSelEnd = totalTextStart + totalTextSize;
  171.     }
  172.  
  173.     // …………………………………………………………… if text edit structure had to be activated earlier, deactivate it
  174.  
  175.     if(!wasActive)
  176.         TEDeactivate(textEditStrucHdl);
  177.  
  178.     return noErr;
  179. }
  180.  
  181. // ******************************************************************** doIsWhiteSpaceAtOffset
  182.  
  183. Boolean  doIsWhiteSpaceAtOffset(SInt16 offset,TEHandle textEditStrucHdl)
  184. {
  185.     char theChar;
  186.  
  187.     if((offset < 0) || (offset > (*textEditStrucHdl)->teLength - 1))
  188.         return true;
  189.  
  190.     theChar = ((char *) *((*textEditStrucHdl)->hText))[offset];
  191.  
  192.     return (doIsWhiteSpace(theChar));
  193. }
  194.  
  195. // **************************************************************************** doIsWhiteSpace
  196.  
  197. Boolean  doIsWhiteSpace(char theChar)
  198. {
  199.     return ((theChar == ' ') || (theChar == 0x0D));
  200. }
  201.  
  202. // ************************************************************************* doGetCharAtOffset
  203.  
  204. char  doGetCharAtOffset(SInt16 offset,TEHandle textEditStrucHdl)
  205. {
  206.     if(offset < 0)
  207.         return 0x0D;
  208.  
  209.     return (((char *) *((*textEditStrucHdl)->hText))[offset]);
  210. }
  211.  
  212. // ********************************************************************** doInsertTextAtOffset
  213.  
  214. SInt16  doInsertTextAtOffset(SInt16 textOffset,Ptr textDataPtr,SInt32 textSize,
  215.                                                          TEHandle textEditStrucHdl)
  216. {
  217.     SInt16    charactersAdded = 0;
  218.  
  219.     if(textSize == 0)
  220.         return charactersAdded;
  221.  
  222.     // …… if inserting at end of word, and selection does not begin with a space, insert a space
  223.  
  224.     if(!doIsWhiteSpaceAtOffset(textOffset - 1,textEditStrucHdl) &&
  225.              doIsWhiteSpaceAtOffset(textOffset,textEditStrucHdl) &&
  226.          !doIsWhiteSpace(textDataPtr[0]))
  227.     {
  228.         TESetSelect(textOffset,textOffset,textEditStrucHdl);
  229.         TEKey(' ',textEditStrucHdl);
  230.         ++textOffset;
  231.         ++charactersAdded;
  232.     }
  233.  
  234.     // … if inserting at beginning of word and selection does not end with a space, insert space
  235.  
  236.     if(doIsWhiteSpaceAtOffset(textOffset - 1,textEditStrucHdl) &&
  237.         !doIsWhiteSpaceAtOffset(textOffset,textEditStrucHdl) &&
  238.         !doIsWhiteSpace(textDataPtr[textSize - 1]))
  239.     {
  240.         TESetSelect(textOffset,textOffset,textEditStrucHdl);
  241.         TEKey(' ',textEditStrucHdl);
  242.         ++charactersAdded;
  243.     }
  244.  
  245.     // …………………………………………………………………………………………………………… before inserting, set selection range to a zero
  246.  
  247.     TESetSelect(textOffset,textOffset,textEditStrucHdl);
  248.     TEInsert(textDataPtr,textSize,textEditStrucHdl);
  249.  
  250.     return charactersAdded;
  251. }
  252.  
  253. // ******************************************************************** doSavePreInsertionText
  254.  
  255. Boolean  doSavePreInsertionText(docStructurePointer    docStrucPtr)
  256. {
  257.     OSErr        osError;
  258.     Size        tempSize;
  259.     Handle    tempTextHdl;
  260.  
  261.     if(docStrucPtr->preDragText == NULL)
  262.         docStrucPtr->preDragText = NewHandle(0);
  263.  
  264.     tempTextHdl = (*(docStrucPtr->textEditStrucHdl))->hText;
  265.     tempSize = GetHandleSize(tempTextHdl);
  266.     SetHandleSize(docStrucPtr->preDragText,tempSize);
  267.     osError = MemError();
  268.     if(osError != noErr)
  269.     {
  270.         doErrorAlert(eDragUndo);
  271.         return false;
  272.     }
  273.  
  274.     BlockMove(*tempTextHdl,*(docStrucPtr->preDragText),tempSize);
  275.  
  276.     docStrucPtr->preDragSelStart = (*((docStrucPtr)->textEditStrucHdl))->selStart;
  277.     docStrucPtr->preDragSelEnd   = (*((docStrucPtr)->textEditStrucHdl))->selEnd;
  278.  
  279.     return true;
  280. }
  281.  
  282. // **************************************************************************** doUndoRedoDrag
  283.  
  284. void  doUndoRedoDrag(WindowRef windowRef)
  285. {
  286.     docStructurePointer    docStrucPtr;
  287.     Handle                            tempTextHdl;
  288.     Rect                                portRect;
  289.     
  290.     docStrucPtr = (docStructurePointer) (GetWRefCon(windowRef));
  291.  
  292.     tempTextHdl = (*(docStrucPtr->textEditStrucHdl))->hText;
  293.     (*(docStrucPtr->textEditStrucHdl))->hText = docStrucPtr->preDragText;
  294.     docStrucPtr->preDragText = tempTextHdl;
  295.  
  296.     if(gUndoFlag)
  297.     {
  298.         (*((docStrucPtr)->textEditStrucHdl))->selStart = docStrucPtr->preDragSelStart;
  299.         (*((docStrucPtr)->textEditStrucHdl))->selEnd = docStrucPtr->preDragSelEnd;
  300.     }
  301.     else
  302.     {
  303.         (*((docStrucPtr)->textEditStrucHdl))->selStart = docStrucPtr->postDropSelStart;
  304.         (*((docStrucPtr)->textEditStrucHdl))->selEnd = docStrucPtr->postDropSelEnd;
  305.     }
  306.  
  307.     gUndoFlag = !gUndoFlag;
  308.  
  309.     TECalText(docStrucPtr->textEditStrucHdl);
  310.     GetWindowPortBounds(windowRef,&portRect);
  311.     InvalWindowRect(windowRef,&portRect);
  312. }
  313.  
  314. // *******************************************************************************************